//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.ruoyi.common.utils.jkalman.jama;

import com.ruoyi.common.utils.jkalman.jama.Matrix;
import com.ruoyi.common.utils.jkalman.jama.util.Maths;

import java.io.Serializable;

public class SingularValueDecomposition implements Serializable {
    private double[][] U;
    private double[][] V;
    private double[] s;
    private int m;
    private int n;

    public SingularValueDecomposition(Matrix Arg) {
        double[][] A = Arg.getArrayCopy();
        this.m = Arg.getRowDimension();
        this.n = Arg.getColumnDimension();
        int nu = Math.min(this.m, this.n);
        this.s = new double[Math.min(this.m + 1, this.n)];
        this.U = new double[this.m][nu];
        this.V = new double[this.n][this.n];
        double[] e = new double[this.n];
        double[] work = new double[this.m];
        boolean wantu = true;
        boolean wantv = true;
        int nct = Math.min(this.m - 1, this.n);
        int nrt = Math.max(0, Math.min(this.n - 2, this.m));

        int p;
        int pp;
        int iter;
        for(p = 0; p < Math.max(nct, nrt); ++p) {
            if (p < nct) {
                this.s[p] = 0.0;

                for(pp = p; pp < this.m; ++pp) {
                    this.s[p] = Maths.hypot(this.s[p], A[pp][p]);
                }

                if (this.s[p] != 0.0) {
                    if (A[p][p] < 0.0) {
                        this.s[p] = -this.s[p];
                    }

                    for(pp = p; pp < this.m; ++pp) {
                        A[pp][p] /= this.s[p];
                    }

                    double var10002 = A[p][p]++;
                }

                this.s[p] = -this.s[p];
            }

            double t;
            int i;
            for(pp = p + 1; pp < this.n; ++pp) {
                if (p < nct & this.s[p] != 0.0) {
                    t = 0.0;

                    for(i = p; i < this.m; ++i) {
                        t += A[i][p] * A[i][pp];
                    }

                    t = -t / A[p][p];

                    for(i = p; i < this.m; ++i) {
                        A[i][pp] += t * A[i][p];
                    }
                }

                e[pp] = A[p][pp];
            }

            if (wantu & p < nct) {
                for(pp = p; pp < this.m; ++pp) {
                    this.U[pp][p] = A[pp][p];
                }
            }

            if (p < nrt) {
                e[p] = 0.0;

                for(pp = p + 1; pp < this.n; ++pp) {
                    e[p] = Maths.hypot(e[p], e[pp]);
                }

                if (e[p] != 0.0) {
                    if (e[p + 1] < 0.0) {
                        e[p] = -e[p];
                    }

                    for(pp = p + 1; pp < this.n; ++pp) {
                        e[pp] /= e[p];
                    }

                    ++e[p + 1];
                }

                e[p] = -e[p];
                if (p + 1 < this.m & e[p] != 0.0) {
                    for(pp = p + 1; pp < this.m; ++pp) {
                        work[pp] = 0.0;
                    }

                    for(pp = p + 1; pp < this.n; ++pp) {
                        for(iter = p + 1; iter < this.m; ++iter) {
                            work[iter] += e[pp] * A[iter][pp];
                        }
                    }

                    for(pp = p + 1; pp < this.n; ++pp) {
                        t = -e[pp] / e[p + 1];

                        for(i = p + 1; i < this.m; ++i) {
                            A[i][pp] += t * work[i];
                        }
                    }
                }

                if (wantv) {
                    for(pp = p + 1; pp < this.n; ++pp) {
                        this.V[pp][p] = e[pp];
                    }
                }
            }
        }

        p = Math.min(this.n, this.m + 1);
        if (nct < this.n) {
            this.s[nct] = A[nct][nct];
        }

        if (this.m < p) {
            this.s[p - 1] = 0.0;
        }

        if (nrt + 1 < p) {
            e[nrt] = A[nrt][p - 1];
        }

        e[p - 1] = 0.0;
        double t;
        int i;
        double[] var10000;
        if (wantu) {
            for(pp = nct; pp < nu; ++pp) {
                for(iter = 0; iter < this.m; ++iter) {
                    this.U[iter][pp] = 0.0;
                }

                this.U[pp][pp] = 1.0;
            }

            for(pp = nct - 1; pp >= 0; --pp) {
                if (this.s[pp] != 0.0) {
                    for(iter = pp + 1; iter < nu; ++iter) {
                        t = 0.0;

                        for(i = pp; i < this.m; ++i) {
                            t += this.U[i][pp] * this.U[i][iter];
                        }

                        t = -t / this.U[pp][pp];

                        for(i = pp; i < this.m; ++i) {
                            var10000 = this.U[i];
                            var10000[iter] += t * this.U[i][pp];
                        }
                    }

                    for(iter = pp; iter < this.m; ++iter) {
                        this.U[iter][pp] = -this.U[iter][pp];
                    }

                    ++this.U[pp][pp];

                    for(iter = 0; iter < pp - 1; ++iter) {
                        this.U[iter][pp] = 0.0;
                    }
                } else {
                    for(iter = 0; iter < this.m; ++iter) {
                        this.U[iter][pp] = 0.0;
                    }

                    this.U[pp][pp] = 1.0;
                }
            }
        }

        if (wantv) {
            for(pp = this.n - 1; pp >= 0; --pp) {
                if (pp < nrt & e[pp] != 0.0) {
                    for(iter = pp + 1; iter < nu; ++iter) {
                        t = 0.0;

                        for(i = pp + 1; i < this.n; ++i) {
                            t += this.V[i][pp] * this.V[i][iter];
                        }

                        t = -t / this.V[pp + 1][pp];

                        for(i = pp + 1; i < this.n; ++i) {
                            var10000 = this.V[i];
                            var10000[iter] += t * this.V[i][pp];
                        }
                    }
                }

                for(iter = 0; iter < this.n; ++iter) {
                    this.V[iter][pp] = 0.0;
                }

                this.V[pp][pp] = 1.0;
            }
        }

        pp = p - 1;
        iter = 0;
        t = Math.pow(2.0, -52.0);
        double tiny = Math.pow(2.0, -966.0);

        while(true) {
            label349:
            while(p > 0) {
                int k;
                for(k = p - 2; k >= -1 && k != -1; --k) {
                    if (Math.abs(e[k]) <= tiny + t * (Math.abs(this.s[k]) + Math.abs(this.s[k + 1]))) {
                        e[k] = 0.0;
                        break;
                    }
                }

                byte kase;
                if (k == p - 2) {
                    kase = 4;
                } else {
                    for(i = p - 1; i >= k && i != k; --i) {
                        t = (i != p ? Math.abs(e[i]) : 0.0) + (i != k + 1 ? Math.abs(e[i - 1]) : 0.0);
                        if (Math.abs(this.s[i]) <= tiny + t * t) {
                            this.s[i] = 0.0;
                            break;
                        }
                    }

                    if (i == k) {
                        kase = 3;
                    } else if (i == p - 1) {
                        kase = 1;
                    } else {
                        kase = 2;
                        k = i;
                    }
                }

                ++k;
                double cs;
                double sn;
                switch (kase) {
                    case 1:
                        t = e[p - 2];
                        e[p - 2] = 0.0;
                        i = p - 2;

                        for(; i >= k; --i) {
                            t = Maths.hypot(this.s[i], t);
                            cs = this.s[i] / t;
                            sn = t / t;
                            this.s[i] = t;
                            if (i != k) {
                                t = -sn * e[i - 1];
                                e[i - 1] = cs * e[i - 1];
                            }

                            if (wantv) {
                                for(i = 0; i < this.n; ++i) {
                                    t = cs * this.V[i][i] + sn * this.V[i][p - 1];
                                    this.V[i][p - 1] = -sn * this.V[i][i] + cs * this.V[i][p - 1];
                                    this.V[i][i] = t;
                                }
                            }
                        }
                        break;
                    case 2:
                        t = e[k - 1];
                        e[k - 1] = 0.0;
                        i = k;

                        while(true) {
                            if (i >= p) {
                                continue label349;
                            }

                            t = Maths.hypot(this.s[i], t);
                            cs = this.s[i] / t;
                            sn = t / t;
                            this.s[i] = t;
                            t = -sn * e[i];
                            e[i] = cs * e[i];
                            if (wantu) {
                                for(i = 0; i < this.m; ++i) {
                                    t = cs * this.U[i][i] + sn * this.U[i][k - 1];
                                    this.U[i][k - 1] = -sn * this.U[i][i] + cs * this.U[i][k - 1];
                                    this.U[i][i] = t;
                                }
                            }

                            ++i;
                        }
                    case 3:
                        t = Math.max(Math.max(Math.max(Math.max(Math.abs(this.s[p - 1]), Math.abs(this.s[p - 2])), Math.abs(e[p - 2])), Math.abs(this.s[k])), Math.abs(e[k]));
                        double sp = this.s[p - 1] / t;
                        double spm1 = this.s[p - 2] / t;
                        double epm1 = e[p - 2] / t;
                        double sk = this.s[k] / t;
                        double ek = e[k] / t;
                        double b = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2.0;
                        double c = sp * epm1 * sp * epm1;
                        double shift = 0.0;
                        if (b != 0.0 | c != 0.0) {
                            shift = Math.sqrt(b * b + c);
                            if (b < 0.0) {
                                shift = -shift;
                            }

                            shift = c / (b + shift);
                        }

                        double f = (sk + sp) * (sk - sp) + shift;
                        double g = sk * ek;

                        for(int j = k; j < p - 1; ++j) {
                            t = Maths.hypot(f, g);
                            cs = f / t;
                            sn = g / t;
                            if (j != k) {
                                e[j - 1] = t;
                            }

                            f = cs * this.s[j] + sn * e[j];
                            e[j] = cs * e[j] - sn * this.s[j];
                            g = sn * this.s[j + 1];
                            this.s[j + 1] = cs * this.s[j + 1];
                            if (wantv) {
                                for(i = 0; i < this.n; ++i) {
                                    t = cs * this.V[i][j] + sn * this.V[i][j + 1];
                                    this.V[i][j + 1] = -sn * this.V[i][j] + cs * this.V[i][j + 1];
                                    this.V[i][j] = t;
                                }
                            }

                            t = Maths.hypot(f, g);
                            cs = f / t;
                            sn = g / t;
                            this.s[j] = t;
                            f = cs * e[j] + sn * this.s[j + 1];
                            this.s[j + 1] = -sn * e[j] + cs * this.s[j + 1];
                            g = sn * e[j + 1];
                            e[j + 1] = cs * e[j + 1];
                            if (wantu && j < this.m - 1) {
                                for(i = 0; i < this.m; ++i) {
                                    t = cs * this.U[i][j] + sn * this.U[i][j + 1];
                                    this.U[i][j + 1] = -sn * this.U[i][j] + cs * this.U[i][j + 1];
                                    this.U[i][j] = t;
                                }
                            }
                        }

                        e[p - 2] = f;
                        ++iter;
                        break;
                    case 4:
                        if (this.s[k] <= 0.0) {
                            this.s[k] = this.s[k] < 0.0 ? -this.s[k] : 0.0;
                            if (wantv) {
                                for(i = 0; i <= pp; ++i) {
                                    this.V[i][k] = -this.V[i][k];
                                }
                            }
                        }

                        for(; k < pp && !(this.s[k] >= this.s[k + 1]); ++k) {
                            t = this.s[k];
                            this.s[k] = this.s[k + 1];
                            this.s[k + 1] = t;
                            if (wantv && k < this.n - 1) {
                                for(i = 0; i < this.n; ++i) {
                                    t = this.V[i][k + 1];
                                    this.V[i][k + 1] = this.V[i][k];
                                    this.V[i][k] = t;
                                }
                            }

                            if (wantu && k < this.m - 1) {
                                for(i = 0; i < this.m; ++i) {
                                    t = this.U[i][k + 1];
                                    this.U[i][k + 1] = this.U[i][k];
                                    this.U[i][k] = t;
                                }
                            }
                        }

                        iter = 0;
                        --p;
                }
            }

            return;
        }
    }

    public Matrix getU() {
        return new Matrix(this.U, this.m, Math.min(this.m + 1, this.n));
    }

    public Matrix getV() {
        return new Matrix(this.V, this.n, this.n);
    }

    public double[] getSingularValues() {
        return this.s;
    }

    public Matrix getS() {
        Matrix X = new Matrix(this.n, this.n);
        double[][] S = X.getArray();

        for(int i = 0; i < this.n; ++i) {
            for(int j = 0; j < this.n; ++j) {
                S[i][j] = 0.0;
            }

            S[i][i] = this.s[i];
        }

        return X;
    }

    public double norm2() {
        return this.s[0];
    }

    public double cond() {
        return this.s[0] / this.s[Math.min(this.m, this.n) - 1];
    }

    public int rank() {
        double eps = Math.pow(2.0, -52.0);
        double tol = (double)Math.max(this.m, this.n) * this.s[0] * eps;
        int r = 0;

        for(int i = 0; i < this.s.length; ++i) {
            if (this.s[i] > tol) {
                ++r;
            }
        }

        return r;
    }
}
